package com.cloudkinto.utils;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import okhttp3.*;
import org.apache.commons.lang.StringUtils;

import javax.net.ssl.*;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.cert.X509Certificate;
import java.util.*;

public class TemuUtils {

    // public static final String url = "https://openapi-b-us.temu.com/ark/router";
    public static final String url = "https://openapi-b-global.temu.com/ark/router";

    //对接仓调用 temu 公共参数：type API 接口名，形如：bg.certified.warehouse.order.status.change
    //                        client_id 调用方的应用标志 app_key，联系 Temu 分配
    //                        target_client_id 实现方的应用标志 app_key，联系 Temu 提供
    //                        timestamp 时间戳，格式为 UNIX 时间（秒）
    //                        sign API 入参参数签名
    //                        data_type  请求返回的数据格式，默认为 JSON 非必传
    public static final String client_id = "97fdeef98e717a2c4f7d0651af7d7602";//调用方的应用标志 app_key，联系 Temu 分配
    public static final String target_client_id = "bd4ccf66c61b69806e0ebe1e544d7e58";//测试环境:b6817d656d6cd7777cacc44fa4990625

    public static final String secret = "a0dbbc7b1302a936fc6c328e2d5347fc9843bdcb";


    //    public static final String target_client_id = "bd4ccf66c61b69806e0ebe1e544d7e58";//线上环境
    //appKey:demo-afb9192897dd2894293e0cae540
    //secret:79790babf98c13b70c16b9881f1c5804be939e5f


    //temu 调用对接仓公共参数：interface_type string 是 形如：bg.certified.warehouse.token.verify
    //                       source_app_key string 是 业务方 key，对接仓不用关注，可以忽略
    //                       target_app_key string 是 对接仓 key，对接仓不用关注，可以忽略
    //                       scene_id string 是 Temu 开平分配的场景，对接仓不用关注
    //                       sign string 是 签名，对接仓可选择是否验签，签名逻辑如下


    /**
     * 发起发起 API 请求 加密
     *
     * @param json
     * @param secretKey
     * @return
     */
    public static String signRequest(String json, String secretKey) {
        Map<String, String> signMap = Maps.newHashMap();
        ObjectMapper mapper = new ObjectMapper();
        try {
            JsonNode jsonNode = mapper.readTree(json);
            final Iterator<Map.Entry<String, JsonNode>> iterator = jsonNode.fields();
            while (iterator.hasNext()) {
                Map.Entry<String, JsonNode> entry = iterator.next();
                JsonNode subNode = entry.getValue();
                if (subNode.isContainerNode()) {
                    signMap.put(entry.getKey(), mapper.writeValueAsString(entry.getValue()));
                } else {
                    signMap.put(entry.getKey(), entry.getValue().asText());
                }
            }
            // 得到签名值 sourceSign
            final Map<String, String> removedSignKeyMap = getSignMap(signMap);
            final String sourceSign = md5(buildSignSource(removedSignKeyMap, secretKey)).toUpperCase();
            System.out.println("sign result : {" + sourceSign + "}");
//            LogUtil.info("sign result : {}", sourceSign);
            return sourceSign;
        } catch (Exception e) {
            return "";
        }
    }

    private static Map<String, String> getSignMap(Map<String, String> bodyMap) {
        Map<String, String> signMap = Maps.newHashMap();
        for (String k : bodyMap.keySet()) {
            if (StringUtils.equals("sign", k)) {
                continue;
            }
            signMap.put(k, bodyMap.get(k));
        }
        return signMap;
    }

    private static String md5(String str) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(str.getBytes(StandardCharsets.UTF_8));
            byte[] result = md.digest();
            final StringBuffer sb = new StringBuffer(32);
            for (final byte b : result) {
                int val = b & 0xff;
                if (val <= 0xf) {
                    sb.append("0");
                }
                sb.append(Integer.toHexString(val));
            }
            return sb.toString();
        } catch (Exception imporsible) {
            throw new AssertionError();
        }
    }

    private static String buildSignSource(Map<String, String> requestParams, String clientSecret) {
        if (null == requestParams || requestParams.isEmpty()) {
            return "";
        }
        Map<String, String> signSrcMap = requestParams;
        // 如果不是 TreeMap 则变成 TreeMap 主要是为了 key 排序
        if (!(requestParams instanceof TreeMap)) {
            signSrcMap = new TreeMap<>(requestParams);
        }
        StringBuilder signSrcBuilder = new StringBuilder().append(clientSecret);
        for (Map.Entry<String, String> entry : signSrcMap.entrySet()) {
            signSrcBuilder.append(entry.getKey()).append(entry.getValue());
        }
        signSrcBuilder.append(clientSecret);
//        LogUtil.info("构建加签源数据 source: {}", signSrcBuilder);
        return signSrcBuilder.toString();
    }


    public static OkHttpClient getUnsafeOkHttpClient() {
        try {
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory, getX509TrustManager());

            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });

            return builder.build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    private static X509TrustManager getX509TrustManager() {
        X509TrustManager x509TrustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {

            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) {

            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }

        };
        return x509TrustManager;
    }

    /**
     * 构建header参数
     *
     * @param headerMap
     * @return
     */
    public static Request.Builder createSPHeader(Map<String, String> headerMap) {
        Request.Builder requestBuilder = new Request.Builder();
        Iterator<Map.Entry<String, String>> pairs =
                headerMap.entrySet().iterator();
        while (pairs.hasNext()) {
            Map.Entry<String, String> data = pairs.next();
            requestBuilder.addHeader(data.getKey(), data.getValue());
        }
        return requestBuilder;
    }

    public static String doPost(String serviceUrl, String token, Map<String, Object> param) throws Exception {
        param.put("type", serviceUrl);
        param.put("client_id", client_id);
        param.put("timestamp", Math.toIntExact(new Date().getTime() / 1000));
        param.put("target_client_id", target_client_id);
        param.put("sign", signRequest(JSON.toJSONString(param), secret));

//        Map<String, Object> apiMap = new HashMap<>();
//        apiMap.put("type", serviceUrl);
//        apiMap.put("client_id", client_id);
//        apiMap.put("timestamp", Math.toIntExact(new Date().getTime() / 1000));
//        apiMap.put("target_client_id", target_client_id);
//        apiMap.put("sign", signRequest(JSON.toJSONString(param), secret));


        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("content-type", "application/json; charset=utf-8");
        OkHttpClient client = getUnsafeOkHttpClient();
//        InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 1081);
//        Proxy proxy = new Proxy(Proxy.Type.HTTP, addr); // http 代理
//        client.newBuilder().proxy(proxy);
        Request.Builder requestBuilder = createSPHeader(headerMap);
//        if (StringUtils.isNotBlank(sign)) {
//            requestBuilder.addHeader("sign", sign);
//        }
        Request request = requestBuilder.url(url)
                .post(RequestBody.create(MediaType.parse("application/json"), JSON.toJSONString(param)))
                .build();
        System.out.println("requestBody:" + JSON.toJSONString(param));
        Response response = null;
        String body = "";
        response = client.newCall(request).execute();
        body = response.body().string();
        System.out.println(body);
        return body;

    }
}
